package cn.bluech.lib.ui.widget.datetimepicker

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.annotation.ColorInt
import androidx.annotation.Dimension
import cn.bluech.lib.R
import cn.bluech.lib.utils.DateUtils
import cn.bluech.lib.utils.DispUtils
import org.jetbrains.annotations.NotNull
import java.util.*
import kotlin.math.min

class DateTimePicker : FrameLayout {
    companion object{
        const val YEAR   = 0
        const val MONTH  = 1
        const val DAY    = 2
        const val HOUR   = 3
        const val MIN    = 4
        const val SECOND = 5
    }

    private var layoutResId = R.layout.layout_date_picker
    private var yearPicker: NumberPicker? = null
    private var monthPicker: NumberPicker? = null
    private var dayPicker: NumberPicker? = null
    private var hourPicker: NumberPicker? = null
    private var minutePicker: NumberPicker? = null
    private var secondPicker: NumberPicker? = null

    private var themeColor = 0
    private var textSize = 0


    private var minTime : Long = 0
    private var maxTime : Long
    private val calendar = Calendar.getInstance() // TimeZone.getTimeZone("UTC")
    //数字格式化，<10的数字前自动加0
    private val formatter =
        NumberPicker.Formatter { value: Int ->
            var str = value.toString()
            if (value < 10) {
                str = "0$str"
            }
            str
        }

    private var listener: ((Long) -> Unit)? = null


    constructor(ctx: Context, attrs: AttributeSet?, defStyle: Int) : super(ctx, attrs,defStyle){
        val attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DateTimePicker)
        themeColor = attributesArray.getColor(R.styleable.DateTimePicker_themeColor,0x000000)
        textSize = DispUtils.px2sp(ctx,
            attributesArray.getDimensionPixelSize(
                R.styleable.DateTimePicker_textSize,
                DispUtils.dp2px(context,15f)
            ).toFloat())
        layoutResId = attributesArray.getResourceId(
            R.styleable.DateTimePicker_layout,
            R.layout.layout_date_picker
        )
        attributesArray.recycle()

        val calendarMax = Calendar.getInstance()
        calendarMax[Calendar.YEAR] = 2100
        maxTime = calendarMax.timeInMillis

        init()
    }

    constructor(ctx: Context, attrs: AttributeSet?) : this(ctx, attrs,0)

    constructor(context: Context) : this(context,null)

    private fun init() {
        removeAllViews()
        try {
            View.inflate(context, layoutResId, this)
        }catch (e:Exception){
            throw Exception("layoutResId is it right or not?")
        }

        yearPicker   = findViewWithTag("yearPicker") // findViewById(R.id.yearPicker)
        monthPicker  = findViewWithTag("monthPicker")
        dayPicker    = findViewWithTag("dayPicker")
        hourPicker   = findViewWithTag("hourPicker")
        minutePicker = findViewWithTag("minutePicker")
        secondPicker = findViewWithTag("secondPicker")
        initPickers()

        setThemeColor(themeColor)
        setTextSize(textSize)


        updateLimit(calendar)
        setDefaultTime(System.currentTimeMillis())
    }

    private fun initPickers(){
        yearPicker?.run {
            isFocusable = true
            isFocusableInTouchMode = true
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //设置NumberPicker不可编辑
            setOnValueChangedListener { _, _, newVal, _ ->
                calendar[Calendar.YEAR] = newVal
                updateLimit(calendar)
                updateTime(calendar) // 这里其实只有day有可能被改变
                listener?.invoke(calendar.timeInMillis)
            }
        }
        monthPicker?.run {
            isFocusable = true
            isFocusableInTouchMode = true
            setFormatter(formatter) //格式化显示数字，个位数前添加0
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener { _, _, newVal, _ ->
                val day = calendar[Calendar.DAY_OF_MONTH]
                if (day>28){
                    // 可能出现跳月现象,如2月只有28天时，设置29号将变成3月1号
                    // 清除日期->修改月份->还原日期
                    calendar[Calendar.DAY_OF_MONTH] = 1
                    calendar[Calendar.MONTH] = newVal-1 // 月份从0开始
                    val dayMax = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
                    calendar[Calendar.DAY_OF_MONTH] = min(day,dayMax)
                }else
                    calendar[Calendar.MONTH] = newVal-1 // 月份从0开始
                updateLimit(calendar)
                updateTime(calendar)
                listener?.invoke(calendar.timeInMillis)
            }
        }
        dayPicker?.run {
            isFocusable = true
            isFocusableInTouchMode = true
            setFormatter(formatter)
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener { _, _, newVal, _ ->
                calendar[Calendar.DAY_OF_MONTH] = newVal
                updateLimit(calendar)
                updateTime(calendar)
                listener?.invoke(calendar.timeInMillis)
            }
        }

        hourPicker?.run {
            isFocusable = true
            isFocusableInTouchMode = true
            setFormatter(formatter)
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener { _, _, newVal, _ ->
                calendar[Calendar.HOUR_OF_DAY] = newVal
                updateLimit(calendar)
                updateTime(calendar)
                listener?.invoke(calendar.timeInMillis)
            }
        }
        minutePicker?.run {
            isFocusable = true
            isFocusableInTouchMode = true
            setFormatter(formatter)
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener { _, _, newVal, _ ->
                calendar[Calendar.MINUTE] = newVal
                updateLimit(calendar)
                updateTime(calendar)
                listener?.invoke(calendar.timeInMillis)
            }
        }
        secondPicker?.run {
            isFocusable = true
            isFocusableInTouchMode = true
            setFormatter(formatter)
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener { _, _, newVal, _ ->
                calendar[Calendar.SECOND] = newVal
                updateLimit(calendar)
                updateTime(calendar)
                listener?.invoke(calendar.timeInMillis)
            }
        }
    }

    private fun updateTime(calendar : Calendar){
        yearPicker?.value = calendar[Calendar.YEAR]
        monthPicker?.value = calendar[Calendar.MONTH]+1 // 月份从0开始
        dayPicker?.value = calendar[Calendar.DAY_OF_MONTH]
        hourPicker?.value = calendar[Calendar.HOUR_OF_DAY]
        minutePicker?.value = calendar[Calendar.MINUTE]
        secondPicker?.value = calendar[Calendar.SECOND]
    }

    private fun updateLimit(calendar : Calendar){
        val calendarMin = Calendar.getInstance()
        val calendarMax = Calendar.getInstance()
        calendarMin.timeInMillis = minTime
        calendarMax.timeInMillis = maxTime

        yearPicker?.run {
            minValue = calendarMin[Calendar.YEAR]
            maxValue = calendarMax[Calendar.YEAR]
        }
        monthPicker?.run {
            minValue = if (DateUtils.sameYear(calendar,calendarMin)){
                calendarMin[Calendar.MONTH]+1
            }else{
                1
            }
            maxValue = if (DateUtils.sameYear(calendar,calendarMax)){
                calendarMax[Calendar.MONTH]+1
            }else{
                12//calendar.getActualMaximum(Calendar.MONTH)+1
            }
            // 调整时间
            val month = calendar[Calendar.MONTH]+1
            if (month<minValue)
                calendar[Calendar.MONTH] = minValue-1
            else if (month>maxValue)
                calendar[Calendar.MONTH] = maxValue-1
        }

        dayPicker?.run {
            minValue = if (DateUtils.sameMonth(calendar,calendarMin)){
                calendarMin[Calendar.DAY_OF_MONTH]
            }else{
                1
            }
            maxValue = if (DateUtils.sameMonth(calendar,calendarMax)){
                calendarMax[Calendar.DAY_OF_MONTH]
            }else{
                calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
            }
            // 调整时间
            val day = calendar[Calendar.DAY_OF_MONTH]
            if (day<minValue)
                calendar[Calendar.DAY_OF_MONTH] = minValue
            else if (day>maxValue)
                calendar[Calendar.DAY_OF_MONTH] = maxValue
        }
        hourPicker?.run {
            minValue = if (DateUtils.sameDay(calendar,calendarMin)){
                calendarMin[Calendar.HOUR_OF_DAY]
            }else{
                0
            }
            maxValue = if (DateUtils.sameDay(calendar,calendarMax)){
                calendarMax[Calendar.HOUR_OF_DAY]
            }else{
                23
            }
            // 调整时间
            val hour = calendar[Calendar.HOUR_OF_DAY]
            if (hour<minValue)
                calendar[Calendar.HOUR_OF_DAY] = minValue
            else if (hour>maxValue)
                calendar[Calendar.HOUR_OF_DAY] = maxValue
        }
        minutePicker?.run {
            minValue = if (DateUtils.sameHour(calendar,calendarMin)){
                calendarMin[Calendar.MINUTE]
            }else{
                0
            }
            maxValue = if (DateUtils.sameHour(calendar,calendarMax)){
                calendarMax[Calendar.MINUTE]
            }else{
                59
            }
            // 调整时间
            val minute = calendar[Calendar.MINUTE]
            if (minute<minValue)
                calendar[Calendar.MINUTE] = minValue
            else if (minute>maxValue)
                calendar[Calendar.MINUTE] = maxValue
        }
        secondPicker?.run {
            minValue = if (DateUtils.sameMinute(calendar,calendarMin)){
                calendarMin[Calendar.SECOND]
            }else{
                0
            }
            maxValue = if (DateUtils.sameMinute(calendar,calendarMax)){
                calendarMax[Calendar.SECOND]
            }else{
                59
            }
            // 调整时间
            val second = calendar[Calendar.SECOND]
            if (second<minValue)
                calendar[Calendar.SECOND] = minValue
            else if (second>maxValue)
                calendar[Calendar.SECOND] = maxValue
        }
    }

    fun getTime():Long{
        // 这个有一定的线程安全问题
        return calendar.timeInMillis
    }

    fun setLayout(@NotNull layout: Int) {
        if (layout == 0)
            return
        layoutResId = layout
        init()
    }

    /**
     * 设置显示类型
     *
     * @param types
     */
    fun setDisplayType(types: IntArray?) {
        if (types == null || types.isEmpty())
            return

        yearPicker?.visibility   = if(types.contains(YEAR))  View.VISIBLE else View.GONE
        monthPicker?.visibility  = if(types.contains(MONTH)) View.VISIBLE else View.GONE
        dayPicker?.visibility    = if(types.contains(DAY))   View.VISIBLE else View.GONE
        hourPicker?.visibility   = if(types.contains(HOUR))  View.VISIBLE else View.GONE
        minutePicker?.visibility = if(types.contains(MIN))   View.VISIBLE else View.GONE
        secondPicker?.visibility = if(types.contains(SECOND))View.VISIBLE else View.GONE
    }
    

    /**
     * 主题颜色
     *
     * @param color
     */
    fun setThemeColor(@ColorInt color: Int) {
        if (color == 0) return
        themeColor = color
        yearPicker?.setTextColor(themeColor)
        monthPicker?.setTextColor(themeColor)
        dayPicker?.setTextColor(themeColor)
        hourPicker?.setTextColor(themeColor)
        minutePicker?.setTextColor(themeColor)
        secondPicker?.setTextColor(themeColor)
    }

    /**
     * 字体大小
     *
     * @param sp
     */
    fun setTextSize(@Dimension sp: Int) {
        if (sp == 0) return
        textSize = sp
        yearPicker?.setTextSize(textSize)
        monthPicker?.setTextSize(textSize)
        dayPicker?.setTextSize(textSize)
        hourPicker?.setTextSize(textSize)
        minutePicker?.setTextSize(textSize)
        secondPicker?.setTextSize(textSize)
    }

    /**
     * 设置标签文字
     */
    fun setLabelText(year: String, month: String, day: String, hour: String, min: String, second: String) {
        yearPicker?.label = year
        monthPicker?.label = month
        dayPicker?.label = day
        hourPicker?.label = hour
        minutePicker?.label = min
        secondPicker?.label = second
    }


    /**
     * 设置Picker循环滚动
     * @param types 需要设置的Picker类型（DateTimeConfig-> YEAR,MONTH,DAY,HOUR,MIN,SECOND）
     */
    fun setWheel(vararg types: Int) {
        yearPicker?.wrapSelectorWheel = YEAR in types
        monthPicker?.wrapSelectorWheel = MONTH in types
        dayPicker?.wrapSelectorWheel = DAY in types
        hourPicker?.wrapSelectorWheel = HOUR in types
        minutePicker?.wrapSelectorWheel = MIN in types
        secondPicker?.wrapSelectorWheel = SECOND in types
    }

    /**
     * 设置最小值
     * 当设置的最小值大于当前的最大值时会自动调整最大值
     */
    fun setMinTime(time: Long) {
        if (time<0)
            return
        // 设置最小值
        minTime = time
        // 调整最大值
        if (maxTime<time)
            maxTime = minTime
        // 调整当前值
        if (calendar.timeInMillis !in minTime .. maxTime){
            calendar.timeInMillis = time
            updateTime(calendar)
        }

        // 更新上下限
        updateLimit(calendar)
    }

    /**
     * 设置最大值
     * 当设置的最大值小于当前的最小值时会自动调整最小值
     */
    fun setMaxTime(time: Long) {
        if (time<0)
            return
        // 设置最大值
        maxTime = time
        // 调整最小值
        if (minTime>time)
            minTime = maxTime
        // 调整当前值
        if (calendar.timeInMillis !in minTime .. maxTime){
            calendar.timeInMillis = time
            updateTime(calendar)
        }

        // 更新上下限
        updateLimit(calendar)
    }

    fun setDefaultTime(time: Long) {
        if (time !in minTime .. maxTime){
            return
        }
        calendar.timeInMillis = time
        updateTime(calendar)
    }


    fun setListener(listener: ((Long) -> Unit)?) {
        this.listener = listener
    }
}